/*
目前而言，流程有三个，分别对应留言、建议、投诉这三类工单类型。
每个流程内部意见类型，可以列出对应的Step供选择，比如：转农产品部处理、转工业品部处理、直接回复等。
*/
package process

import (
	"errors"
	"fmt"
	dao2 "gitee.com/baal1990/gitee.com/baal1990/cmd/server/app/dao"
	entity2 "gitee.com/baal1990/gitee.com/baal1990/cmd/server/app/entity"
	"gitee.com/baal1990/gitee.com/baal1990/cmd/server/app/global"
	"gitee.com/baal1990/gitee.com/baal1990/pkg/model"
	"github.com/gin-gonic/gin"
	"go.uber.org/zap"
	"net/http"
	"strconv"
	"strings"
)

func IdListStringToInt64(idstr string) []int64 {
	var ids []int64
	strList := strings.Split(idstr, ";")
	if len(strList) == 0 {
		return ids
	}
	for _, str := range strList {
		id, err := strconv.ParseInt(str, 10, 64)
		if err == nil {
			ids = append(ids, id)
		}
	}
	return ids
}

//根据工单，智能选择流程
func IntelligentSearchProcess(order *entity2.WorkOrder) ([]*entity2.Process, error) {
	if order != nil {
		return nil, errors.New("order is nil")
	}

	if order.OpinionType < entity2.EOpinionType_Unknown ||
		order.OpinionType > entity2.EOpinionType_MarketService {
		return nil, errors.New("unknown option type")
	}

	if order.WorkOrderType < entity2.EWorkOrderType_Unknown ||
		order.WorkOrderType > entity2.EWorkOrderType_Complaint {
		return nil, errors.New("unknown work order type")
	}

	objs, err := dao2.SearchProcess(order.OpinionType, order.WorkOrderType)
	if err != nil {
		global.Log.Error("dao.QueryProcessList error:", zap.Any("error", err))
		return nil, err
	}

	return objs, nil
}

//根据工单号，搜索匹配的流程
func IntelligentSearchProcessByOrderId(orderId int64) ([]*entity2.Process, error) {
	if orderId <= 0 {
		return nil, errors.New("Work order not specified")
	}

	order, err := dao2.QueryWorkOrderDetail(orderId)
	if err != nil {
		return nil, err
	}
	return IntelligentSearchProcess(order)
}

//根据工单类型搜索匹配流程
func SearchProcessByOrderType(orderType entity2.EWorkOrderType) ([]*entity2.Process, error) {
	if orderType <= entity2.EWorkOrderType_Unknown ||
		orderType > entity2.EWorkOrderType_Complaint {
		return nil, errors.New("Work order type not specified")
	}
	processList, err := dao2.SearchProcess(entity2.EOpinionType_Unknown, orderType)
	return processList, err
}

//搜索工单对应的流程
func SearchProcessForWorkOrder(c *gin.Context) {
	workOrderId, err := strconv.ParseInt(c.DefaultQuery("workOrderId", ""), 10, 64)
	if err != nil {
		global.Log.Error("work order is lost.")
		c.JSON(http.StatusOK, model.Fail("未指明工单"))
		return
	}
	processList, err := IntelligentSearchProcessByOrderId(workOrderId)
	if err != nil {
		c.JSON(http.StatusOK, model.Fail("未找到匹配的流程"))
		return
	}
	c.JSON(http.StatusOK, model.SuccessObject("操作成功", processList))
	return
}

//搜索制定流程中的对应步骤列表，返回step列表
func SearchStepForProcess(c *gin.Context) {

	workOrderId, err := strconv.ParseInt(c.DefaultQuery("workOrderId", ""), 10, 64)
	if err != nil {
		global.Log.Error("work order is lost.")
		c.JSON(http.StatusOK, model.Fail("未指明工单"))
		return
	}

	processId, err := strconv.ParseInt(c.DefaultQuery("processId", ""), 10, 64)
	if err != nil {
		global.Log.Error("work order is lost.")
		c.JSON(http.StatusOK, model.Fail("未指明工单"))
		return
	}
	global.Log.Info("SearchStepForProcess input params.", zap.Any("workOrderId", workOrderId), zap.Any("processId", processId))

	processDetail, err := dao2.QueryProcessDetail(processId)
	if err != nil {
		c.JSON(http.StatusOK, model.Fail("未找到流程中的步骤列表"))
		return
	}
	if len(processDetail.StepIds) <= 0 {
		c.JSON(http.StatusOK, model.Fail("流程中未配置步骤信息"))
		return
	}

	stepIdList := IdListStringToInt64(processDetail.StepIds)

	_, allSteps, err := dao2.QueryStepList(1, 0)
	if err != nil {
		c.JSON(http.StatusOK, model.Fail("流程中未配置步骤信息"))
		return
	}

	type StepList struct { //列表查询输出
		Total int64
		List  []*entity2.Step
	}
	output := &StepList{
		Total: 0,
	}

	for _, stepInfo := range allSteps {
		for _, id := range stepIdList {
			if stepInfo.StepId == id {
				output.List = append(output.List, stepInfo) //找到了一个，输出
				output.Total++
			}
		}
	}

	c.JSON(http.StatusOK, model.SuccessObject("操作成功", output))
	return
}

//添加新流程
//POST
func CreateProcess(c *gin.Context) {
	var process entity2.Process
	process.ProcessName = strings.TrimSpace(c.DefaultPostForm("processName", "")) //标题
	if len(process.ProcessName) <= 0 {
		global.Log.Error("CreateProcess name is none.")
		c.JSON(http.StatusOK, model.Fail("流程名称不能为空"))
		return
	}

	process.Readme = c.DefaultPostForm("readme", "")

	opinionTypesStr := c.DefaultPostForm("opinionTypeArray", "")     //本流程所适用的留言类型列表
	workOrderTypesStr := c.DefaultPostForm("workOrderTypeArray", "") //本流程所适用的留言类型列表
	stepIdsStr := c.DefaultPostForm("stepIdArray", "")               //本流程所包含的步骤ID列表

	process.OpinionTypes = opinionTypesStr
	process.WorkOrderTypes = workOrderTypesStr
	process.StepIds = stepIdsStr
	/*
		opinionTypeArray := strings.Split(opinionTypesStr,";")
		orderTypeArray := strings.Split(workOrderTypesStr,";")	//
		stepIdArray := strings.Split(stepIdsStr,";")

		for _,t := range opinionTypeArray{		//本流程所适用的留言类型列表
			tt,_:=strconv.Atoi(t)
			process.OpinionTypes = append(process.OpinionTypes,entity.EOpinionType(tt) )
		}
		for _,o := range orderTypeArray{		//本流程所适用的工单型列表
			oo,_:=strconv.Atoi(o)
			process.WorkOrderTypes = append(process.WorkOrderTypes,entity.EWorkOrderType(oo) )
		}
		for _,idStr := range stepIdArray{	//本流程所包含的步骤ID列表
			id,_ := strconv.ParseInt(idStr , 10, 64)
			process.StepIds = append(process.StepIds,id)
		}
	*/
	newstep, err := dao2.InsertProcess(process)
	if err != nil {
		global.Log.Error("CreateStep failed.", zap.Any("error", err))
		c.JSON(http.StatusOK, model.Fail("添加步骤失败"))
	} else {
		c.JSON(http.StatusOK, model.SuccessObject("操作成功", newstep))
		global.Log.Info("CreateStep success.", zap.Any("new step", newstep))
	}
}

//更新流程
//POST
func UpdateProcess(c *gin.Context) {
	var process entity2.Process
	var err error

	process.ProcessId, err = strconv.ParseInt(c.DefaultQuery("processId", ""), 10, 64)
	if err != nil {
		global.Log.Error("UpdateProcess processId is lost.")
		c.JSON(http.StatusOK, model.Fail("未指明要更新的流程"))
		return
	}

	process.ProcessName = strings.TrimSpace(c.DefaultPostForm("processName", "")) //标题
	if len(process.ProcessName) <= 0 {
		global.Log.Error("UpdateProcess name is none.")
		c.JSON(http.StatusOK, model.Fail("流程名称不能为空"))
		return
	}

	opinionTypesStr := c.DefaultPostForm("opinionTypeArray", "")   //本流程所适用的留言类型列表
	workOrderTypesStr := c.DefaultPostForm("opinionTypeArray", "") //本流程所适用的留言类型列表
	stepIdsStr := c.DefaultPostForm("stepIdArray", "")             //本流程所包含的步骤ID列表

	process.OpinionTypes = opinionTypesStr
	process.WorkOrderTypes = workOrderTypesStr
	process.StepIds = stepIdsStr
	/*
		opinionTypeArray := strings.Split(opinionTypesStr,";")
		orderTypeArray := strings.Split(workOrderTypesStr,";")	//
		stepIdArray := strings.Split(stepIdsStr,";")
		for _,t := range opinionTypeArray{		//本流程所适用的留言类型列表
			tt,_:=strconv.Atoi(t)
			process.OpinionTypes = append(process.OpinionTypes,entity.EOpinionType(tt) )
		}
		for _,o := range orderTypeArray{		//本流程所适用的工单型列表
			oo,_:=strconv.Atoi(o)
			process.WorkOrderTypes = append(process.WorkOrderTypes,entity.EWorkOrderType(oo) )
		}
		for _,idStr := range stepIdArray{	//本流程所包含的步骤ID列表
			id,_ := strconv.ParseInt(idStr , 10, 64)
			process.StepIds = append(process.StepIds,id)
		}
	*/

	newprocess, err := dao2.UpdateProcess(process)
	if err != nil {
		global.Log.Error("UpdateProcess failed.", zap.Any("error", err))
		c.JSON(http.StatusOK, model.Fail("添加步骤失败"))
	} else {
		c.JSON(http.StatusOK, model.SuccessObject("操作成功", newprocess))
		global.Log.Info("UpdateProcess success.", zap.Any("new step", newprocess))
	}
}

//移除流程
//DELETE
func DeleteProcess(c *gin.Context) {
	processId, err := strconv.ParseInt(c.DefaultQuery("processId", ""), 10, 64)
	if err != nil {
		global.Log.Error("DeleteStep stepId is lost.")
		c.JSON(http.StatusOK, model.Fail("删除流程步骤失败"))
		return
	}

	err = dao2.DeleteProcess(processId)
	if err != nil {
		global.Log.Error("DeleteProcess failed.", zap.Any("error", err))
		c.JSON(http.StatusOK, model.Fail("添加步骤失败"))
	} else {
		c.JSON(http.StatusOK, model.Success("删除步骤成功"))
		global.Log.Info("DeleteProcess success.", zap.Any("processId", processId))
	}
}

//查询流程
//GET
func QueryProcessDetail(c *gin.Context) {
	processId, err := strconv.ParseInt(c.DefaultQuery("processId", ""), 10, 64)
	if err != nil {
		global.Log.Error("QueryProcessDetail stepId is lost.")
		c.JSON(http.StatusOK, model.Fail("未指明要查询的流程步骤"))
		return
	}

	obj, err := dao2.QueryProcessDetail(processId)
	if err != nil {
		global.Log.Error("dao.QueryProcessDetail error:", zap.Any("error", err))
		c.JSON(http.StatusOK, model.FailCustomer("操作失败", err))
		return
	}
	c.JSON(http.StatusOK, model.SuccessObject("操作成功", obj))
	return
}

func QueryAllProcess(c *gin.Context) {
	pageSize, err1 := strconv.Atoi(c.DefaultQuery("pageSize", "10"))
	if err1 != nil {
		global.Log.Error("QueryAllProcess input param pagesize error:", zap.Any("error", err1))
		c.JSON(http.StatusOK, model.Fail("请求参数错误"))
		return
	}

	page, err2 := strconv.Atoi(c.DefaultQuery("page", "1"))
	if err2 != nil {
		global.Log.Error("QueryAllProcess input param page error:", zap.Any("error", err2))
		c.JSON(http.StatusOK, model.Fail("请求参数错误"))
		return
	}

	total, objs, err := dao2.QueryProcessList(page, pageSize)
	if err != nil {
		global.Log.Error("dao.QueryProcessList error:", zap.Any("error", err))
		c.JSON(http.StatusOK, model.FailCustomer("操作失败", err))
		return
	}
	type ProcessList struct { //列表查询输出
		Total int64
		List  []*entity2.Process
	}

	output := &ProcessList{
		Total: total,
		List:  objs,
	}
	global.Log.Info("dao.QueryProcessList success :", zap.Any("output", output))
	c.JSON(http.StatusOK, model.SuccessObject("操作成功", output))
	return
}

//新建步骤
//POST
func CreateStep(c *gin.Context) {
	var step entity2.Step
	step.StepName = strings.TrimSpace(c.DefaultPostForm("stepname", "")) //标题
	if len(step.StepName) <= 0 {
		global.Log.Error("CreateStep name is none.")
		c.JSON(http.StatusOK, model.Fail("步骤名称不能为空"))
		return
	}

	ttt := c.DefaultPostForm("deptId", "")
	fmt.Println(ttt)
	var err error
	step.DeptId, err = strconv.ParseInt(c.DefaultPostForm("deptId", ""), 10, 64)
	if err != nil {
		global.Log.Error("CreateStep deptid is lost.")
		c.JSON(http.StatusOK, model.Fail("需指定处理部门"))
		return
	}

	newstep, err := dao2.InsertStep(step)
	if err != nil {
		global.Log.Error("CreateStep failed.", zap.Any("error", err))
		c.JSON(http.StatusOK, model.Fail("添加步骤失败"))
	} else {
		c.JSON(http.StatusOK, model.SuccessObject("操作成功", newstep))
		global.Log.Info("CreateStep success.", zap.Any("new step", newstep))
	}
}

//新建步骤
//POST
func UpdateStep(c *gin.Context) {
	var step entity2.Step
	step.StepName = strings.TrimSpace(c.DefaultPostForm("stepname", "")) //标题
	if len(step.StepName) <= 0 {
		global.Log.Error("UpdateStep name is none.")
		c.JSON(http.StatusOK, model.Fail("步骤名称不能为空"))
		return
	}

	ttt := c.DefaultPostForm("deptId", "")
	fmt.Println(ttt)
	var err error
	step.DeptId, err = strconv.ParseInt(c.DefaultPostForm("deptId", ""), 10, 64)
	if err != nil {
		global.Log.Error("UpdateStep deptid is lost.")
		c.JSON(http.StatusOK, model.Fail("需指定处理部门"))
		return
	}

	newstep, err := dao2.UpdateStep(step)
	if err != nil {
		global.Log.Error("UpdateStep failed.", zap.Any("error", err))
		c.JSON(http.StatusOK, model.Fail("添加步骤失败"))
	} else {
		c.JSON(http.StatusOK, model.SuccessObject("操作成功", newstep))
		global.Log.Info("UpdateStep success.", zap.Any("new step", newstep))
	}
}

//删除指定步骤（管理员才能删，以后得校验权限）
//POST
func DeleteStep(c *gin.Context) {
	stepId, err := strconv.ParseInt(c.DefaultQuery("stepId", ""), 10, 64)
	if err != nil {
		global.Log.Error("DeleteStep stepId is lost.")
		c.JSON(http.StatusOK, model.Fail("删除流程步骤失败"))
		return
	}

	err = dao2.DeleteStep(stepId)
	if err != nil {
		global.Log.Error("DeleteStep failed.", zap.Any("error", err))
		c.JSON(http.StatusOK, model.Fail("添加步骤失败"))
	} else {
		c.JSON(http.StatusOK, model.Success("删除步骤成功"))
		global.Log.Info("DeleteStep success.", zap.Any("stepId", stepId))
	}
}

func QueryAllSteps(c *gin.Context) {
	pageSize, err1 := strconv.Atoi(c.DefaultQuery("pageSize", "10"))
	if err1 != nil {
		global.Log.Error("QueryAllSteps input param pagesize error:", zap.Any("error", err1))
		c.JSON(http.StatusOK, model.Fail("请求参数错误"))
		return
	}

	page, err2 := strconv.Atoi(c.DefaultQuery("page", "1"))
	if err2 != nil {
		global.Log.Error("QueryAllSteps input param page error:", zap.Any("error", err2))
		c.JSON(http.StatusOK, model.Fail("请求参数错误"))
		return
	}

	total, steps, err := dao2.QueryStepList(page, pageSize)
	if err != nil {
		global.Log.Error("dao.QueryStepList error:", zap.Any("error", err))
		c.JSON(http.StatusOK, model.FailCustomer("操作失败", err))
		return
	}
	type StepList struct { //列表查询输出
		Total int64
		List  []*entity2.Step
	}
	output := &StepList{
		Total: total,
		List:  steps,
	}

	c.JSON(http.StatusOK, model.SuccessObject("操作成功", output))
	return
}

func QueryStepDetail(c *gin.Context) {
	stepId, err := strconv.ParseInt(c.DefaultQuery("stepId", ""), 10, 64)
	if err != nil {
		global.Log.Error("QueryStepDetail stepId is lost.")
		c.JSON(http.StatusOK, model.Fail("未指明要查询的流程步骤"))
		return
	}

	step, err := dao2.QueryStepDetail(stepId)
	if err != nil {
		global.Log.Error("dao.QueryStepDetail error:", zap.Any("error", err))
		c.JSON(http.StatusOK, model.FailCustomer("操作失败", err))
		return
	}
	c.JSON(http.StatusOK, model.SuccessObject("操作成功", step))
	return
}

//添加步骤到流程
//GET
func AddStepToPrecess(c *gin.Context) {

}
